<?

/*****************************************************************************

Heartdropper Responder 0.0.3
Copyright (C) 2013 by Jacob Rose

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

HOW TO USE

To reset the list (preventing any past messages from affectin the
game), send:
http://heartdropper.com/?service=reset

Your first pull should look like this:
http://heartdropper.com/?service=fetch&request[id]=0

After the first go, put the highest ID you got from me at the end
there instead of 0. 

If you want to use *poll* mode, the request will linger until a tweet
shows up or the timeout is reached -- the only difference is you send
'service=poll' instead of 'service=fetch'

*****************************************************************************/

/* Some configuration globals */
$MESSAGE_POLL_TIMEOUT = 1; /* Timeout in seconds before client needs to retry */
$MESSAGE_POLL_RESPONSIVENESS = 200000; /* IMPORTANT: this is the responsiveness of chat in microseconds */
$MESSAGE_POLL_MAXIMUM_TRIES = floor( $MESSAGE_POLL_TIMEOUT * 1000000 / $MESSAGE_POLL_RESPONSIVENESS );

class heartdropper
{
	function __construct()
	{
		include "MySQLPasswords.php";
		$this->db = new PDO(
			'mysql:host=' . $MYSQL_HOSTNAME . ';' .
			'dbname=' . $MYSQL_DATABASE . ';' .
			'port=' . $MYSQL_PORT,
		        $MYSQL_USERNAME,
		        $MYSQL_PASSWORD
		);
	}

	/* reset() clears the twitter history */
	function reset( $request )
	{
		$this->_do_sql("UPDATE twitter SET deleted='y'");
	}

	function avatar( $request )
	{
		if ( ! array_key_exists( 'username', $request ) )
			return array( 'error' => 'NO_USERNAME_PROVIDED' );

		$get_avatar = $this->_do_sql(
			"SELECT profile_image, image_content_type FROM twitter_users " .
			"INNER JOIN twitter_user_avatars USING ( profile_image_url ) " .
			"WHERE twitter_users.twitter_user_name = ?",
			array(
				$request['username']
			)
		);

		if ( is_array( $get_avatar ) && array_key_exists( 0, $get_avatar ) )
		{
			/* Generic content reply; body and type only */
			return array(
				'success' => 1,
				'content_type' => $get_avatar[0]['image_content_type'],
				'content' => $get_avatar[0]['profile_image']
			);
		}
	}

	/* poll() waits for the next message sent by any user and then returns it */
	function poll( $request )
	{
		global $MESSAGE_POLL_MAXIMUM_TRIES, $MESSAGE_POLL_RESPONSIVENESS;

		/* Keep checking for new data until it arrives... */
		$tries = 0; /* ...but timeout if we try too many times */
		while
			(
				(
					! $this->_do_sql(
						"SELECT 1 FROM twitter where twitter_synthetic_id > ? AND deleted='n' " .
						"AND twitter.parsed_building IS NOT NULL AND twitter.parsed_building <> '' " .
						"AND twitter.parsed_bonus IS NOT NULL AND twitter.parsed_bonus <> ''",
						array( $request['id'] )
					)
				)
				&&
				( $tries < $MESSAGE_POLL_MAXIMUM_TRIES )
			)
		{
			usleep( $MESSAGE_POLL_RESPONSIVENESS ); 
			$tries++;
		}

		/* Send back a special message alerting client if we timed out */
		if ( $tries >= $MESSAGE_POLL_MAXIMUM_TRIES )
		{
			return( array( timeout => 1 ) );
		}

		/* Luckily, fetch() will also check that our session is still good after all that waiting */
		return $this->fetch( $request );
	}

	/* fetch() sends all chat history since $request['since_message_id'] to the client */
	function fetch( $request )
	{
		$new_messages = $this->_do_sql(
			'SELECT twitter.twitter_synthetic_id as id, twitter.parsed_building AS building, ' .
			'twitter_users.twitter_user_name as username, twitter.parsed_bonus AS bonus, twitter.text ' .
			'FROM twitter ' .
			'INNER JOIN twitter_users ON ( twitter.from_user_id = twitter_users.twitter_user_id ) ' .
			"WHERE twitter.twitter_synthetic_id > ? AND twitter.deleted='n'" .
			"AND twitter.parsed_building IS NOT NULL AND twitter.parsed_building <> ''" .
			"AND twitter.parsed_bonus IS NOT NULL AND twitter.parsed_bonus <> ''" .
			'ORDER BY twitter.twitter_synthetic_id ASC',
			array( $request['id'] )
		);

		if ( $new_messages )
		{
			return( array( success => 1, tweets => $new_messages ) );
		}
		else
		{
			return( array( error => 'NO_NEW_TWEETS' ) );
		}
	}


	/* Unfortunately, we throw away every query we construct, yet prepare() is
	the only way to get decent placeholder support in PHP; this little function
	takes the grunt work out of preparing and executing statements and returns
	only the results (if there are any) or success/failure for non-SELECTs */
	function _do_sql( $query, $parameters = NULL )
	{
		$prepared_query = $this->db->prepare( $query );
		if ( is_array( $parameters ) )
		{
			if ( ! $prepared_query->execute( $parameters ) )
				return;
		}
		else
		{
			if ( ! $prepared_query->execute() )
				return;
		}

		/* If the query was expected to return something... */
		if ( preg_match( '/select/i', $query ) )
			/* ...fetch results */
			return $prepared_query->fetchAll();
		else
			/* ...otherwise, we know it didn't fail, so return true */
			return true;
	}
}
